﻿using System;
using System.Collections.Generic;
using System.Text;

namespace JSH.ITDiplom.OOPC01.PersonalIdentityNumber.BusinessLayer.se
{
    /// <summary>
    /// This class is used to validate and generate Swedish personal identity numbers.
    /// See http://en.wikipedia.org/wiki/Personal_identity_number_(Sweden) for a
    /// description of the swedish personal identity number.
    /// </summary>
    public sealed class SwedishPersonalIdentityNumber : PersonalIdentityNumber
    {
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="personalIdentityNumber">Personal identity number</param>
        public SwedishPersonalIdentityNumber(string personalIdentityNumber) 
            : base(personalIdentityNumber)
        {
            SetBirthDay();
            SetGender();
            validations = new IPersonalIdentityNumberValidation[3];
            validations[0] = new FormatValidation(personalIdentityNumber);
            validations[1] = new DateValidation(BirthDay);
            validations[2] = new ChecksumValidation(personalIdentityNumber);
        }

        /// <summary>
        /// Calc. birthday and set property.
        /// </summary>
        private void SetBirthDay()
        {
            try
            {
                int fullYear = GetFullYear();
                DateTime date = new DateTime(fullYear,
                    Int32.Parse(personalIdentityNumber.Substring(2, 2)),
                    Int32.Parse(personalIdentityNumber.Substring(0, 2)));
                BirthDay = date;
            }
            catch
            {
                BirthDay = null;
            }
        }

        /// <summary>
        /// Calc. gender and set property.
        /// </summary>
        private void SetGender()
        {
            try
            {
                int digit11 = 
                    Int32.Parse(personalIdentityNumber.Substring(9, 1));
                int remainder = digit11 % 2;
                if (remainder == 0)
                {
                    Gender = Gender.Female;
                }
                else
                {
                    Gender = Gender.Male;
                }
            }
            catch
            {
                Gender = Gender.Unknown;
            }
        }

        /// <summary>
        /// Calc full birthday year.
        /// </summary>
        /// <returns></returns>
        private int GetFullYear()
        {
            DateTime now = DateTime.Today;
            int year = now.Year;
            int firstPart = year/100; 
            int secondPart = year - firstPart*100;
            int yearPartFromPersonalIdentityNumber = 
                Int32.Parse(personalIdentityNumber.Substring(4, 2));
            if (yearPartFromPersonalIdentityNumber <= secondPart)
            {
                if (personalIdentityNumber[6] == '+') //Person over 100 years old
                {
                    firstPart--;
                }                
            }
            else
            {
                if (personalIdentityNumber[6] == '+') //Person over 100 years old
                {
                    firstPart = firstPart - 2;
                }
                else
                {
                    firstPart--;
                }
            }
            return (firstPart*100) + yearPartFromPersonalIdentityNumber;
        }

        /// <summary>
        /// Generate personal identity numbers.
        /// </summary>
        /// <param name="birthday">Birthday</param>
        /// <param name="gender">Gender (Male or Female)</param>
        /// <returns>A list of valid personal identity numbers</returns>
        public static IList<string> Generate(DateTime birthday, Gender gender)
        {
            int age = DateTime.Now.Year - birthday.Year;
            if (age > 199)
            {
                throw new ArgumentException("Age over 199");
            }
            IList<string> personalNumbers = new List<string>();
            StringBuilder sb = new StringBuilder();
            int day = birthday.Day;
            if (day < 10) sb.Append("0");
            sb.Append(day);
            int month = birthday.Month;
            if (month < 10) sb.Append("0");
            sb.Append(month);
            int year = birthday.Year;
            int lowYearPart = year % 100;
            if (lowYearPart < 10) sb.Append("0");
            sb.Append(lowYearPart);
            if (age < 100)
            {
                sb.Append("-");
            }
            else
            {
                sb.Append("+");
            }
            string fixedPart = sb.ToString();
            int startFrom = 0;
            if (gender == Gender.Male)
            {
                startFrom = 1;
            }
            for (int i = startFrom; i < 1000; i=i+2)
            {
                StringBuilder personalNumber = new StringBuilder(fixedPart);
                if (i < 100) personalNumber.Append("0");
                if (i < 10) personalNumber.Append("0");
                personalNumber.Append(i);
                personalNumber.Append(
                    ChecksumValidation.Calculate(personalNumber.ToString()));
                personalNumbers.Add(personalNumber.ToString());
            }
            return personalNumbers;
        }
    }
}